package com.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.controller.common.PcReported;
import com.controller.reqdto.InstructParam;
import com.controller.reqdto.PcAddParam;
import com.controller.reqdto.PcQueryParam;
import com.controller.reqdto.PcUpdateParam;
import com.controller.reqdto.report.PcReportDataQuery;
import com.controller.reqdto.report.PcReportParam;
import com.controller.respdto.PcList;
import com.controller.respdto.PcReportedList;
import com.enums.CommonEnum;
import com.repository.mapper.*;
import com.repository.po.*;
import com.service.PcService;
import com.util.WebsocketUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Ruiwen
 * @since 2024-11-19
 */
@Service
@Slf4j
public class PcServiceImpl implements PcService {
    @Resource
    PcMessageMapper pcMessageMapper;
    @Resource
    AddressMapper addressMapper;
    @Resource
    PcReportedDataMapper pcReportedDataMapper;
    @Resource
    PcGroupRelationshipMapper pcGroupRelationshipMapper;
    @Resource
    GroupMsgMapper groupMsgMapper;


    @Override
    public PcList canUsePcList() {
        List<PcMessage> pcMessages = pcMessageMapper.selectList(null);
        return PcList.builder().pcMessages(pcMessages).build();
    }

    @Override
    public PcList queryPcList(PcQueryParam queryParam) {
        Page<PcMessage> page = new Page<PcMessage>(queryParam.getPage(), queryParam.getLimit());
        QueryWrapper<PcMessage> queryWrapper = new QueryWrapper<>();
        if (Objects.nonNull(queryParam.getPcName())) {
            queryWrapper.like("pc_name", queryParam.getPcName());
        }
        if (Objects.nonNull(queryParam.getPcStatus())) {
            queryWrapper.eq("pc_status", queryParam.getPcStatus());
        }
        if (Objects.nonNull(queryParam.getCreateEndTime())) {
            queryWrapper.le("create_time", queryParam.getCreateEndTime());
        }
        if (Objects.nonNull(queryParam.getCreateStartTime())) {
            queryWrapper.ge("create_time", queryParam.getCreateStartTime());
        }
        if (Objects.nonNull(queryParam.getAddressId())) {
            queryWrapper.eq("address_id", queryParam.getAddressId());
        }
        List<PcMessage> pcMessages = pcMessageMapper.selectPage(page, queryWrapper).getRecords();
        //遍历pc列表，获取对应的地址信息
        pcMessages.forEach(pcMessage -> {
            if (Objects.nonNull(pcMessage.getAddressId())) {
                Address address = addressMapper.selectById(pcMessage.getAddressId());
                if (Objects.nonNull(address)) {
                    pcMessage.setAddressName(address.getName());
                    pcMessage.setAddress(address.getAddress());
                } else {
                    pcMessage.setAddressName("暂无地区");
                    pcMessage.setAddress("暂无地区地址");
                }

            }

        });
        return PcList.builder().pcMessages(pcMessages).total(page.getTotal()).build();
    }

    @Override
    public Boolean updatePcMsg(PcUpdateParam updateParam) {
        PcMessage pcMessage = new PcMessage();
        BeanUtils.copyProperties(updateParam, pcMessage);
        return pcMessageMapper.updateById(pcMessage) > 0;
    }

    @Override
    public Boolean deletePc(Integer id) {
        //todo 检验没做
        return pcMessageMapper.deleteById(id) > 0;

    }

    @Override
    public Boolean addPc(PcAddParam pcAddParam) {
        List<PcMessage> uniqueKey = pcMessageMapper.selectList(new QueryWrapper<PcMessage>().eq("pc_unique_key", pcAddParam.getPcUniqueKey()));
        if (uniqueKey.size() > 0) {
            throw new RuntimeException("PC主机唯一标识重复，请勿重复添加");
        }
        PcMessage pcMessage = new PcMessage();
        BeanUtils.copyProperties(pcAddParam, pcMessage);
        pcMessage.setPcStatus(CommonEnum.PC_NOT_RUN.getCode());
        return pcMessageMapper.insert(pcMessage) > 0;
    }

    @Override
    public void pcMsgReport(PcReportParam pcReportParam) {
        if (Objects.isNull(pcReportParam) || Objects.isNull(pcReportParam.getPcUniqueKey())) {
            throw new RuntimeException("上报数据不能为空/PC主机唯一标识不能为空");
        }
        PcMessage pcMessage = pcMessageMapper.selectOne(new QueryWrapper<PcMessage>().eq("pc_unique_key", pcReportParam.getPcUniqueKey()));
        if (Objects.isNull(pcMessage)) {
            log.info("PC主机唯一标识不存在，将自动添加");
            pcMessage = new PcMessage();
            pcMessage.setPcName("WithOutName new PC ");
            pcMessage.setPcUniqueKey(pcReportParam.getPcUniqueKey());
            pcMessage.setPcStatus(CommonEnum.PC_NOT_RUN.getCode());
            pcMessageMapper.insert(pcMessage);
        }
        if (pcMessage.getPcStatus().equals(CommonEnum.PC_STATUS_ERROR.getCode())) {
            pcMessage.setPcStatus(CommonEnum.PC_NOT_RUN.getCode());
            pcMessageMapper.updateById(pcMessage);
        }
        log.info("记录上报数据");
        pcReportedDataMapper.insert(PcReportedData.builder()
                .pcId(pcMessage.getId())
                .pcUniqueKey(pcMessage.getPcUniqueKey())
                .pcReportMsg(JSONObject.toJSONString(pcReportParam))
                .build());


    }

    @Override
    public PcReportedList queryPcReportData(PcReportDataQuery pcReportDataQuery) {
        Integer pcId = null;
        if (Objects.nonNull(pcReportDataQuery.getPcName())) {
            PcMessage pcMessage = pcMessageMapper.selectOne(new QueryWrapper<PcMessage>().eq("pc_name", pcReportDataQuery.getPcName()));
            if (Objects.nonNull(pcMessage)) {
                pcId = pcMessage.getId();
            }
        }
        Page<PcReportedData> page = new Page<>(pcReportDataQuery.getPage(), pcReportDataQuery.getLimit());
        QueryWrapper<PcReportedData> queryWrapper = new QueryWrapper<>();
        if (Objects.nonNull(pcId)) {
            queryWrapper.eq("pc_id", pcId);
        }
        Page<PcReportedData> pcReportedDataPage = pcReportedDataMapper.selectPage(page, queryWrapper);
        if (pcReportedDataPage.getRecords().size() == 0) {
            return PcReportedList.builder().pcReportedList(null).total(0).build();
        }
        List<PcReportedData> pcReportedDataList = pcReportedDataPage.getRecords();
        List<PcReported> pcReportedList = new ArrayList<>();
        for (PcReportedData pcReportedData : pcReportedDataList) {
            PcMessage pcMessage = pcMessageMapper.selectById(pcReportedData.getPcId());
            if (Objects.isNull(pcMessage)) {
                continue;
            }
            pcReportedList.add(PcReported.builder()
                    .id(pcReportedData.getId())
                    .pcId(pcReportedData.getPcId())
                    .pcName(pcMessage.getPcName())
                    .pcUniqueKey(pcMessage.getPcUniqueKey())
                    .pcReportMsg(JSONObject.parseObject(pcReportedData.getPcReportMsg(), PcReportParam.class))
                    .createTime(pcReportedData.getCreateTime())
                    .updateTime(pcReportedData.getUpdateTime())
                    .build());
        }
        //pack
        return PcReportedList.builder().pcReportedList(pcReportedList).total(pcReportedDataPage.getTotal()).build();


    }

    @Override
    public Void control(InstructParam instructParam) {
        Integer paramType = instructParam.getParamType();
        switch (paramType) {
            case 0:
                groupControl(instructParam);
                break;
            case 1:
                pcControl(instructParam);
                break;
            case 2:
                batchPcControl(instructParam);
                break;
            default:
                throw new RuntimeException("指令类型错误");
        }
        return null;
    }

    @Override
    public PcReported queryPcReportDataById(Integer pcId) {
        //根据pcId 查出一条最新的数据
        PcReportedData pcReportedData = pcReportedDataMapper.selectOne(new QueryWrapper<PcReportedData>().eq("pc_id", pcId).orderByDesc("create_time").last("limit 1"));

        PcMessage pcMessage = pcMessageMapper.selectById(pcReportedData.getPcId());
        if (Objects.isNull(pcMessage)) {
            return null;
        }
        return PcReported.builder()
                .id(pcReportedData.getId())
                .pcId(pcReportedData.getPcId())
                .pcName(pcMessage.getPcName())
                .pcUniqueKey(pcMessage.getPcUniqueKey())
                .pcReportMsg(JSONObject.parseObject(pcReportedData.getPcReportMsg(), PcReportParam.class))
                .createTime(pcReportedData.getCreateTime())
                .updateTime(pcReportedData.getUpdateTime())
                .build();
    }


    private void groupControl(InstructParam instructParam) {
        List<PcGroupRelationship> pcGroupRelationships = pcGroupRelationshipMapper.selectList(new QueryWrapper<PcGroupRelationship>().eq("group_id", instructParam.getId()));
        if (pcGroupRelationships.size() == 0) {
            throw new RuntimeException("分组不存在");
        }
        for (PcGroupRelationship pcGroupRelationship : pcGroupRelationships) {
            PcMessage pcMessage = pcMessageMapper.selectById(pcGroupRelationship.getPcId());
            if (Objects.nonNull(pcMessage)) {
                sendInstruct(pcMessage.getPcUniqueKey(), instructParam.getMsg());
            }
            PcMessage updatePc = new PcMessage();
            updatePc.setId(pcMessage.getId());
            if (instructParam.isOpen()) {
                updatePc.setPcStatus(CommonEnum.PC_RUNNING.getCode());
                pcMessage.setRunTime(new Date());
            } else {
                updatePc.setPcStatus(CommonEnum.PC_NOT_RUN.getCode());
                pcMessage.setEndTime(new Date());
            }
            pcMessageMapper.updateById(updatePc);
        }
        GroupMsg groupMsg = new GroupMsg();
        groupMsg.setId(instructParam.getId());
        groupMsg.setGroupStatus(instructParam.getGroupStatus());
        if (instructParam.isOpen()) groupMsg.setRunTime(new Date());
        else groupMsg.setEndTime(new Date());
        groupMsgMapper.updateById(groupMsg);

    }


    private void pcControl(InstructParam instructParam) {

        PcGroupRelationship pcGroupRelationship = pcGroupRelationshipMapper.selectOne(new QueryWrapper<PcGroupRelationship>().eq("pc_id", instructParam.getId()).orderByDesc("create_time").last("limit 1"));
        if (Objects.isNull(pcGroupRelationship)) {
            throw new RuntimeException("分组不存在");
        }
        PcMessage pcMessage = pcMessageMapper.selectById(instructParam.getId());
        if (Objects.nonNull(pcMessage)) {
            sendInstruct(pcMessage.getPcUniqueKey(), instructParam.getMsg());
        }
        PcMessage updatePc = new PcMessage();
        updatePc.setId(pcMessage.getId());
        if (instructParam.isOpen()) {
            updatePc.setPcStatus(CommonEnum.PC_RUNNING.getCode());
            pcMessage.setRunTime(new Date());
        } else {
            updatePc.setPcStatus(CommonEnum.PC_NOT_RUN.getCode());
            pcMessage.setEndTime(new Date());
        }
        pcMessageMapper.updateById(updatePc);
        pcGroupRelationshipMapper.deleteById(pcGroupRelationship.getId());
        List<PcGroupRelationship> pcGroupRelationshipsList = pcGroupRelationshipMapper.selectList(new QueryWrapper<PcGroupRelationship>().eq("group_id", pcGroupRelationship.getGroupId()));
        if (pcGroupRelationshipsList.size() == 0) {
            GroupMsg groupMsg = new GroupMsg();
            groupMsg.setId(pcGroupRelationship.getGroupId());
            groupMsg.setGroupStatus(instructParam.getGroupStatus());
            if (instructParam.isOpen()) groupMsg.setRunTime(new Date());
            else groupMsg.setEndTime(new Date());
            groupMsgMapper.updateById(groupMsg);
        }


    }

    private void batchPcControl(InstructParam instructParam) {
    }

    private void sendInstruct(String key, String msg) {
        WebsocketUtil.sendMessage(key, msg);
    }
}
